<template>
  <div class="canvas" ref="canvasEditRef" @mousedown="($event) => handleClickBlankArea($event)"
    v-contextmenu="contextmenus" v-click-outside="removeEditorAreaFocus">
    <ElementCreateSelection v-if="creatingElement" ref="createselection"
      @created="(data:any) => insertElementFromCreateSelection(data)" />
    <div class="viewport-wrapper" :style="`
      top: ${!MultiPage ? '50%' : '0'};
      margin-top: ${
        !MultiPage ? `-${(canvasHeight * canvasScale) / 2}px` : '0'
      };
      width: ${canvasWidth * canvasScale}px;
      height: ${canvasHeight * canvasScale}px;
      left: 50%;
      margin-left: -${(canvasWidth * canvasScale) / 2}px;
      outline: ${dragIndex === index ? 'rgb(255, 186, 0) dashed 2px' : ''}
    `" :class="{ active: slideIndex === index }" v-for="(item, index) in slides" :key="index"
      v-show="!MultiPage ? index == 0 : true" @mousedown="($event) => changSlideIndex($event, index)"
      @drop="drop($event)" @dragover="allowDrop($event, index)" @dragleave="leaveDrop">
      <div v-if="MultiPage">
        <div class="page" :style="`color:${slideIndex === index ? '#fff' : ''}`">
          第{{ index + 1 }}页/共{{ slides.length }}页
        </div>
        <div class="icongroup">
          <i class="appIcon-iconfont appIcon-quanbuyemian-fuzhimoren" @click="copyPage(slideIndex)"></i>
          <i class="appIcon-iconfont appIcon-yemian-shanchumoren" v-if="slides.length > 1"
            @click="delPage(slideIndex)"></i>
        </div>
      </div>
      <!-- <div class="resize resizetop" @mousedown="mousedown($event, 'top')"></div> -->
      <!-- <div class="resize resizebot" @mouseover="mouseover=true" @mouseleave="mouseover=false" @mousedown="mousedown($event, 'bot')">
        <dd></dd>
      </div>
      <div class="resize resizeLeft" @mouseover="mouseover=true" @mouseleave="mouseover=false" :style="`opacity:${mouseover? 1 : 0}`" @mousedown="mousedown($event, 'left')">
        <dd></dd>
      </div>
      <div class="resize resizeRight" @mouseover="mouseover=true" @mouseleave="mouseover=false" :style="`opacity:${mouseover? 1 : 0}`" @mousedown="mousedown($event, 'right')">
        <dd></dd>
      </div> -->
      <div class="btn" v-if="MultiPage" @click="addPage">添加页面</div>

      <div class="viewport-content" @mousedown="handlePage">
        <div class="operates">
          <AlignmentLine v-for="(line, index) in alignmentLines" :key="index" :type="line.type" :axis="line.axis"
            :length="line.length" />
          <div v-if="slideIndex === index">
            <MultiSelectOperate v-if="activeElementIdList.length > 1" :elementList="elementList"
              :scaleMultiElement="scaleMultiElement" />
          </div>

          <div v-if="slideIndex === index">
            <Operate v-for="element in elementList" :key="element.id" :elementInfo="element"
              :isSelected="activeElementIdList.includes(element.id)" :isActive="handleElementId === element.id"
              :isActiveGroupElement="activeGroupElementId === element.id"
              :isMultiSelect="activeElementIdList.length > 1" :rotateElement="rotateElement"
              :scaleElement="scaleElement" :openLinkDialog="openLinkDialog" :dragLineElement="dragLineElement" />
          </div>
          <div v-else>
            <Operate v-for="element in item.elements" :key="element.id" :elementInfo="element"
              :isSelected="activeElementIdList.includes(element.id)" :isActive="handleElementId === element.id"
              :isActiveGroupElement="activeGroupElementId === element.id"
              :isMultiSelect="activeElementIdList.length > 1" :rotateElement="rotateElement"
              :scaleElement="scaleElement" :openLinkDialog="openLinkDialog" :dragLineElement="dragLineElement" />
          </div>
          <ViewportBackground :currentId="index" />
        </div>

        <div class="viewport" :ref="`${slideIndex === index ? 'viewportRef' : ''}`"
          :style="{ transform: `scale(${canvasScale})`}">
          <!-- slideIndex === index //判断是否为当前页面  -->
          <div v-if="slideIndex === index">
            <MouseSelection v-if="mouseSelectionState.isShow" :top="mouseSelectionState.top"
              :left="mouseSelectionState.left" :width="mouseSelectionState.width" :height="mouseSelectionState.height"
              :quadrant="mouseSelectionState.quadrant" />
            <EditableElement v-for="(element, index) in elementList" :key="element.id" :elementInfo="element"
              :elementIndex="index + 1" :isMultiSelect="activeElementIdList.length > 1" :selectElement="selectElement"
              :openLinkDialog="openLinkDialog" />
          </div>
          <div v-else>
            <EditableElement v-for="(element, index) in item.elements" :key="element.id" :elementInfo="element"
              :elementIndex="index + 1" :isMultiSelect="activeElementIdList.length > 1" :selectElement="selectElement"
              :openLinkDialog="openLinkDialog" />
          </div>
        </div>
      </div>
    </div>

    <Ruler :viewportStyles="viewportStyles" v-if="showRuler" />

    <Modal v-model:visible="linkDialogVisible" :footer="null" centered :width="540" destroyOnClose>
      <LinkDialog @close="linkDialogVisible = false" />
    </Modal>
  </div>
</template>

<script lang="ts">
import {
  defineComponent,
  nextTick,
  onMounted,
  onUnmounted,
  onBeforeUnmount,
  provide,
  ref,
  watch,
  watchEffect,
  reactive,
} from "vue";
import { throttle } from "lodash";
import { storeToRefs } from "pinia";
import {
  useMainStore,
  useSlidesStore,
  useKeyboardStore,
  useScreenStore,
} from "@/store";
import { ContextmenuItem } from "@/components/Contextmenu/types";
import { PPTElement } from "@/types/slides";
import { AlignmentLineProps } from "@/types/edit";
import { removeAllRanges } from "@/utils/selection";
import { KEYS } from "@/configs/hotkey";

import useViewportSize from "./hooks/useViewportSize";
import useMouseSelection from "./hooks/useMouseSelection";
import useDropImageOrText from "./hooks/useDropImageOrText";
import useRotateElement from "./hooks/useRotateElement";
import useScaleElement from "./hooks/useScaleElement";
import useSelectElement from "./hooks/useSelectElement";
import useDragElement from "./hooks/useDragElement";
import useDragLineElement from "./hooks/useDragLineElement";
import useInsertFromCreateSelection from "./hooks/useInsertFromCreateSelection";

import useDeleteElement from "@/hooks/useDeleteElement";
import useCopyAndPasteElement from "@/hooks/useCopyAndPasteElement";
import useSelectAllElement from "@/hooks/useSelectAllElement";
import useScaleCanvas from "@/hooks/useScaleCanvas";
import useScreening from "@/hooks/useScreening";
import useSlideHandler from "@/hooks/useSlideHandler";

import EditableElement from "./EditableElement.vue";
import MouseSelection from "./MouseSelection.vue";
import ViewportBackground from "./ViewportBackground.vue"; //背景
import AlignmentLine from "./AlignmentLine.vue"; //参考线
import Ruler from "./SketchRuler.vue"; // 标尺
import ElementCreateSelection from "./ElementCreateSelection.vue";
import MultiSelectOperate from "./Operate/MultiSelectOperate.vue"; // 组合元素操作
import Operate from "./Operate/index.vue"; // 单个元素操作
import LinkDialog from "./LinkDialog.vue";
import emitter, { EmitterEvents } from "@/utils/emitter";
// 协同
import { initWebSocket, sendData, closewebsocket } from "@/utils/webScoket";
import { useRoute } from "vue-router";

export default defineComponent({
  name: "editor-canvas",
  components: {
    EditableElement,
    MouseSelection,
    ViewportBackground,
    AlignmentLine,
    Ruler,
    ElementCreateSelection,
    MultiSelectOperate,
    Operate,
    LinkDialog,
  },
  setup() {
    const mainStore = useMainStore();
    const edtype = ref(process.env.VUE_APP_EDITOR_TYPE);
    const {
      activeElementIdList,
      activeGroupElementId,
      handleElementId,
      handleElement,
      editorAreaFocus,
      showGridLines,
      creatingElement,
      canvasScale,
      handleElementOtherIdList, // 在线人员列表
      showRuler, // 是否显示标尺
      EditorType, //编辑器类型
    } = storeToRefs(mainStore);
    const { ctrlKeyState, ctrlOrShiftKeyActive, deleteKeyState } = storeToRefs(
      useKeyboardStore()
    );
    const { currentSlide, slideIndex, slides } = storeToRefs(useSlidesStore());

    const MultiPage = ref(false); //是否为多页面
    watch(
      () => EditorType.value,
      (val: any) => {
        if(val == '2' || val == '3') { //自由编辑器和ppt显示多页面
          MultiPage.value = true
        }
      },
      {immediate: true}
    )
    const pageList = ref<any>([]);
    // watch(
    //   () => MultiPage.value,
    //   (val) => {
    //     console.log(slides,'slides')
    //     val ? pageList.value = slides.value : pageList.value = slides.value[0]
    //   },
    //   {immediate: true}
    // )
    /**
     * 协同所需
     */
    const route = useRoute();
    const userinfo = localStorage.getItem("userInfo");
    const userId = userinfo ? JSON.parse(userinfo).hhxsUserId : "";

    const obj: any = reactive({
      lockNodeId: "",
      removeSlideId: 0,
      // 是否分析完全部页面
      isUpdataSlide: 0,
      // 是否正在处理推送消息
      wsProcessing: false,
      // 是否正在处理推送消息
      wsLastMsg: "",
    });
    /*
      ws连接，
    **/

    // "wss:///pptWss?authorization=" +
    //  "ws://10.1.40.20:8834/ppt?authorization=" +

    let wsUrl: string =
      "wss:///pptWss?authorization=" +
      localStorage.getItem("token") +
      "&officeMainId=" +
      route.query.id;
    let isEdit: any = false;

    onMounted(() => {
      if (route.query.id) {
        initWebSocket(wsUrl, websocketonmessage);
        isEdit = true;
      }
      emitter.on(EmitterEvents.SET_CANVAS_SIZE, setCanvasSize);
      emitter.on(EmitterEvents.INSERT_ELEMENT, insertEle);
    });
    onBeforeUnmount(() => {
      emitter.off(EmitterEvents.INSERT_ELEMENT, insertEle);
      emitter.off(EmitterEvents.SET_CANVAS_SIZE, setCanvasSize);
      if (isEdit) {
        closewebsocket();
      }
    });
    /**
      数据发送
    */
    const sendmessage = ref(false);

    //数据接收
    const websocketonmessage: any = (e: any) => {
      let resData: any = JSON.parse(e.data).data;
      let resCode: number = resData.operationType;
      let userList = JSON.parse(
        JSON.stringify(mainStore.handleElementOtherIdList)
      );
      let operationIndex: any = userList.findIndex(
        (item: any) => item.userid == resData.operatorId
      );

      /**
       * 初始化数据不作处理
       * 我自己发送的消息不作处理
       * 心跳不作处理
       */

      if (
        resCode == 9999 ||
        (resCode != 1002 &&
          resCode != 6001 &&
          resCode != 5003 &&
          resData.operatorId &&
          userId == resData.operatorId)
      ) {
        return;
      }

      // 获取全部json
      if (resCode == 1002) {
        useSlidesStore().setSlides(JSON.parse(resData.content));
        return;
      }

      // 获取在线用户列表
      if (resCode == 6001) {
        let userList: any = [];
        JSON.parse(resData.content).forEach((item: any) => {
          userList.push({
            userid: item.hhxsUserId,
            inPageId: item.inPageId,
            username: item.nickName,
            userAvatar: item.userAvatar,
            handleElementId: "",
          });
        });
        // 将数据添加至vuex
        mainStore.setHandleElementOtherIdList(userList);
        return;
      }

      // 用户上线
      if (resCode == 6004) {
        if (
          mainStore.handleElementOtherIdList.findIndex(
            (item: any) => item.userid == JSON.parse(resData.content).hhxsUserId
          ) != -1
        )
          return;
        let newUserInfo: any = {
          userid: JSON.parse(resData.content).hhxsUserId,
          inPageId: JSON.parse(resData.content).inPageId,
          username: JSON.parse(resData.content).nickName,
          userAvatar: JSON.parse(resData.content).userAvatar,
          handleElementId: "",
        };
        // 修改在线用户列表
        mainStore.setHandleElementOtherIdList([
          ...mainStore.handleElementOtherIdList,
          newUserInfo,
        ]);
        return;
      }

      // 用户下线
      if (resCode == 6003) {
        // let operationIndex: any = userList.findIndex(
        //   (item: any) => item.userid == resData.operationId
        // );
        userList.splice(operationIndex, 1);
        // 修改在线用户列表
        mainStore.setHandleElementOtherIdList(userList);
        return;
      }

      // 用户锁定节点
      if (resCode == 5001) {
        userList[operationIndex].handleElementId = resData.lockName;
        // 修改在线用户列表
        mainStore.setHandleElementOtherIdList(userList);
        return;
      }

      // 用户解锁节点
      if (resCode == 5002) {
        userList[operationIndex].handleElementId = "";
        // 将数据添加至vuex
        mainStore.setHandleElementOtherIdList(userList);
        return;
      }

      // 获取全部锁信息
      if (resCode == 5003) {
        // console.log(JSON.parse(resData.content));
        if (JSON.parse(resData.content).length != 0) {
          JSON.parse(resData.content).forEach((item: any) => {
            let operationIndexLet: any = userList.findIndex(
              (citem: any) => citem.userid == item.operatorId
            );
            if (userList[operationIndexLet]) {
              userList[operationIndexLet].handleElementId = item.lockName;
            }
          });
        }
        mainStore.setHandleElementOtherIdList(userList);
        return;
      }

      if (resCode == 3001) {
        // console.log("有用户新增节点");
        let resContent = JSON.parse(resData.content);
        let slideIndex = resData.operationTargetIndex.slice(
          0,
          resData.operationTargetIndex.indexOf(".")
        );
        useSlidesStore().addIndexElement(slideIndex, { ...resContent });
        return;
      }

      if (resCode == 3002) {
        // console.log("有用户删除节点");
        let slideIndex = resData.operationTargetIndex.slice(
          0,
          resData.operationTargetIndex.indexOf(".")
        );
        useSlidesStore().removeElement(
          slideIndex,
          slides.value[slideIndex].elements.findIndex(
            (item: any) => item.id === resData.operationId
          )
        );
        return;
      }

      if (resCode == 3003) {
        // console.log("服务端返回的ID", resData.operatorId);
        // console.log("浏览器缓存的ID", userId);
        // console.log("浏览器缓存的ID", "663641841301376");

        // console.log("有用户更新节点数据");

        let slideIndex = resData.operationTargetIndex.slice(
          0,
          resData.operationTargetIndex.indexOf(".")
        );
        obj.wsLastMsg = resData.content;

        let resContent = JSON.parse(resData.content);
        useSlidesStore().updateIndexElement(slideIndex, {
          id: resContent.id,
          props: { ...resContent },
        });

        return;
      }

      if (resCode == 2001) {
        // console.log("有用户新增页面");
        let resContent = JSON.parse(resData.content);
        if (
          slides.value.findIndex((item: any) => item.id == resContent.id) != -1
        )
          return;
        useSlidesStore().addSlideIndex(
          JSON.parse(resData.content),
          resData.targetIndex
        );
        return;
      }

      if (resCode == 2002) {
        // console.log("有用户删除页面");
        obj.removeSlideId = resData.operationId;
        let sildeIndex = slides.value.findIndex(
          (item: any) => item.id == resData.operationId
        );
        useSlidesStore().removeSilde(sildeIndex);
        return;
      }

      if (resCode == 4001) {
        // console.log("有用户修改页面属性");
        let slideIndex = resData.operationTargetIndex.slice(
          0,
          resData.operationTargetIndex.indexOf(".")
        );
        obj.wsLastMsg = resData.content;
        if (resData.operatorId == userId) return;

        if (JSON.parse(resData.content) instanceof Array) {
          // console.log("有用户修改节点动画");
          useSlidesStore().updateIndexSlide(slideIndex, {
            animations: JSON.parse(resData.content),
          });
          return;
        }

        if (JSON.parse(resData.content) instanceof Object) {
          // console.log("有用户修改页面颜色");
          useSlidesStore().updateIndexSlide(slideIndex, {
            background: JSON.parse(resData.content),
          });
          return;
        }

        if (typeof JSON.parse(resData.content) == "string") {
          // console.log("有用户修改页面过度");
          useSlidesStore().updateIndexSlide(slideIndex, {
            turningMode: JSON.parse(resData.content),
          });
          return;
        }

        return;
      }

      if (resCode == 4002) {
        obj.wsLastMsg = resData.content;
        if (resData.operatorId == userId) return;

        if (resData.operationTargetIndex == "background") {
          // console.log("有用户批量页面背景色");
          slides.value.forEach((item: any, index: number) => {
            useSlidesStore().updateIndexSlide(index, {
              background: JSON.parse(resData.content),
            });
          });
          return;
        }

        if (resData.operationTargetIndex == "turningMode") {
          // console.log("有用户批量页面过渡效果");
          slides.value.forEach((item: any, index: number) => {
            useSlidesStore().updateIndexSlide(index, {
              turningMode: JSON.parse(resData.content),
            });
          });
          return;
        }
      }
    };

    // 监听页面数量发生变化
    watch(
      () => [[...slides.value], slideIndex.value],
      (n: any, o: any) => {
        if (!route.query.id) return;
        // 首次进入原始json不做消息同步
        if (
          o[0].length == 1 &&
          o[0][0].elements.length == 0 &&
          o[0][0].background.type == "solid" &&
          o[0][0].background.color == "#ffffff"
        ) {
          return;
        }

        if (o[1] > n[1] && o[0].length == n[0].length) {
          // console.log("页面排序");
        }

        if (n[0].length > o[0].length && n[1] != o[1]) {
          // console.log("新增页面");
          sendData(
            JSON.stringify({
              operationType: 2001,
              targetIndex: n[1],
              content: JSON.stringify(n[0][n[1]]),
            })
          );
          return;
        }

        if (n[0].length < o[0].length) {
          // console.log("删除页数");
          if (o[0].findIndex((item: any) => item.id == obj.removeSlideId) != -1)
            return;
          sendData(
            JSON.stringify({
              operationType: 2002,
              operationId: o[0][o[1]].id,
            })
          );
          return;
        }
      },
      { deep: true }
    );

    // 监听当前页面数据变化
    watch(
      () => [{ ...currentSlide.value }, { ...handleElement.value }],
      (n: any, o: any) => {
        if (!route.query.id) return;

        let val = n[0];
        let oldval = o[0];
        let eleVal = n[1];
        let oldEleVal = (0)[1];
        if (
          handleElementId.value &&
          oldval.elements.findIndex(
            (item: any) => item.id === handleElementId.value
          ) == -1
        ) {
          // console.log("如果老数据中不包含当前节点时，则为新增节点");
          sendData(
            JSON.stringify({
              operationType: 3001,
              operationTargetIndex: slideIndex.value + ".elements",
              content: JSON.stringify(val.elements[val.elements.length - 1]),
            })
          );
          return;
        }

        if (
          JSON.stringify(oldval.background) != JSON.stringify(val.background)
        ) {
          // console.log("ppt当前页面背景色发生变化");
          if (
            oldval.background.type == "solid" &&
            oldval.background.color == "#ffffff"
          ) {
            return;
          }

          // ws返回的消息是否已经处理
          if (JSON.stringify(val.background) == obj.wsLastMsg) {
            obj.wsLastMsg = "";
            return;
          }
          sendData(
            JSON.stringify({
              operationType: 4001,
              operationTargetIndex: slideIndex.value + ".background",
              content: JSON.stringify(val.background),
            })
          );
          return;
        }

        if (oldval.turningMode != val.turningMode) {
          // console.log("页面过渡效果发生变化");
          if (oldval.turningMode == "") return;
          // ws返回的消息是否已经处理
          if (JSON.stringify(val.turningMode) == obj.wsLastMsg) {
            obj.wsLastMsg = "";
            return;
          }
          sendData(
            JSON.stringify({
              operationType: 4001,
              operationTargetIndex: slideIndex.value + ".turningMode",
              content: JSON.stringify(val.turningMode),
            })
          );
          return;
        }

        if (
          JSON.stringify(oldval.animations) != JSON.stringify(val.animations)
        ) {
          // console.log("节点动画发生变化");
          if (oldval.animations && oldval.animations.length == 0) return;
          // ws返回的消息是否已经处理
          if (JSON.stringify(val.animations) == obj.wsLastMsg) {
            obj.wsLastMsg = "";
            return;
          }
          sendData(
            JSON.stringify({
              operationType: 4001,
              operationTargetIndex: slideIndex.value + ".animations",
              content: JSON.stringify(val.animations),
            })
          );
          return;
        }

        // // 层级关系发生变化的时候同步
        // if (
        //   JSON.stringify(val) != JSON.stringify(oldval) &&
        //   val.elements &&
        //   val.elements.length === oldval.elements.length
        // ) {
        //   console.log("层级关系发生变化的时候同步");
        //   console.log(oldval);
        //   console.log(val);
        //   console.log(oldEleVal);
        //   console.log(eleVal);
        //   // sendData(
        //   //   JSON.stringify({
        //   //     operationType: 3004,
        //   //     operationId: handleElement.id,
        //   //     operationTargetIndex: slideIndex.value + ".background",
        //   //     content: JSON.stringify(content),
        //   //     targetIndex: 0,
        //   //   })
        //   // );
        //   return;
        // }

        return;

        if (
          JSON.stringify(val) != JSON.stringify(oldval) &&
          val.animations &&
          JSON.stringify(val.animations) !== JSON.stringify(oldval.animations)
        ) {
          // console.log("动画发生变化");
          // 动画发生变化
          // sendData(
          //   JSON.stringify({
          //     cmd: 1001, //消息类型，大于1000
          //     sendType: 1, // 0 个人 1 群发 2 全部
          //     userId: userId,
          //     chatId: obj.pageJson.id, // pptId
          //     message: JSON.stringify({
          //       Data: val.animations,
          //       slideIndex: slideIndex.value,
          //       animations: true,
          //     }),
          //   })
          // );
          return;
        }
      },
      { deep: true }
    );

    // 点击当前元素触发，用于锁定当前节点，并且更新当前节点的属性
    watch(
      () => handleElement.value,
      (val: any, oldval: any) => {
        if (!route.query.id) return;
        if (oldval == null && val == null) return;
        /**
         * 当前操作的页面: slideIndex.value
         * 当前操作的节点ID: handleElementId.value
         * 当前操作的节点: handleElement.value
         * 判断是否为删除操作: deleteKeyState.value
         */

        if (oldval && val && oldval.id != val.id) {
          // console.log("切换节点");
          // console.log("1，解锁节点");
          sendData(
            JSON.stringify({
              operationType: 5002,
              lockName: oldval.id,
            })
          );
          // console.log("锁定节点");
          sendData(
            JSON.stringify({
              operationType: 5001,
              lockName: val.id,
            })
          );
          return;
        }

        if (deleteKeyState.value) {
          // console.log("删除当前节点");
          sendData(
            JSON.stringify({
              operationType: 3002,
              operationId: oldval.id,
              operationTargetIndex: slideIndex.value + ".elements",
            })
          );
          return;
        }

        if (!oldval && val) {
          // console.log("2，锁定节点");
          sendData(
            JSON.stringify({
              operationType: 5001,
              lockName: handleElementId.value,
            })
          );
          obj.lockNodeId = handleElementId.value;
          return;
        }

        // console.log(handleElementId.value);
        // console.log(val && val.id);

        // // 如果新老数据不同表示节点内数据发生变化
        // console.log(oldval != val);
        // // 区分是否为移动，
        // console.log(handleElementId.value);
        // // 区分发生变化的节点是否是我选中的节点
        // console.log(val && handleElementId.value == val.id);

        // console.log(handleElementId.value);
        // console.log(
        //   Boolean(
        //     val &&
        //       handleElementId.value == val.id &&
        //       oldval != val &&
        //       handleElementId.value
        //   )
        // );
        if (
          val &&
          handleElementId.value == val.id &&
          oldval != val &&
          handleElementId.value
        ) {
          // if (oldval) {
          // console.log("更新节点");
          let currentElementIndex =
            slideIndex.value +
            ".elements." +
            currentSlide.value.elements.findIndex(
              (item: any) => item.id == handleElementId.value
            );

          // if (JSON.stringify(handleElement.value) == obj.wsLastMsg) {
          //   obj.wsLastMsg = "";
          //   return;
          // }
          sendData(
            JSON.stringify({
              operationType: 3003,
              operationTargetIndex: currentElementIndex,
              content: JSON.stringify(val),
            })
          );
          return;
        }

        // console.log(oldval);
        // console.log(val);

        if (oldval && !val) {
          // console.log("解锁节点");
          sendData(
            JSON.stringify({
              operationType: 5002,
              // lockName: obj.lockNodeId,
              lockName: handleElementId.value,
            })
          );
          obj.lockNodeId = "";
        }
      },
      { deep: true }
    );

    const addPage = async () => {
      await createSlide();
      scrollToCurrent();
    };
    const drop = (e: MouseEvent) => {
      e.preventDefault();
    };
    const dragIndex = ref();
    watch(
      () => mainStore.dragIndex,
      (val) => {
        dragIndex.value = mainStore.dragIndex;
      }
    );
    const leaveDrop = () => {
      mainStore.setDragIndex("");
      mainStore.setCurrentTab(0);
      // console.log(mainStore.currentTab,'---')
    };
    //拖拽元素后放到拖拽的页面
    const allowDrop = (e: MouseEvent, index: number) => {
      e.preventDefault();
      mainStore.setDragIndex(index);
      if (slideIndex.value === index) return;
      slidesStore.updateSlideIndex(index);
    };
    const copyPage = (slideId: number) => {
      copyAndPasteSlide();
      nextTick(() => {
        scrollToCurrent();
      });
    };
    const delPage = (slideId: number) => {
      deleteSlide();
    };
    // 切换页面
    const changSlideIndex = (e: MouseEvent, index: number) => {
      e.stopPropagation();
      // console.log('changSlideIndex')
      if (!ctrlOrShiftKeyActive.value) updateMouseSelection(e);
      mainStore.setActiveElementIdList([]);
      if (slideIndex.value === index) return;
      slidesStore.updateSlideIndex(index);
      scrollToCurrent();
    };
    const handlePage = () => {
      slidesStore.$patch({
        blankArea: false,
      });
      mainStore.$patch({
        currentTab: 0,
      });
    };
    const mouseover = ref(false);
    const slidesStore = useSlidesStore();
    const screenStore = useScreenStore();
    const canvasEditRef = ref<HTMLElement>();
    const { viewportStyles } = useViewportSize(canvasEditRef);
    const canvasWidth = ref(mainStore.canvasWidth);
    const canvasHeight = ref(mainStore.canvasHeight);
    const canvasTop = ref();
    const canvasLeft = ref();
    let height = mainStore.canvasHeight;
    let width = mainStore.canvasWidth;
    let left = 0;
    let top = 0;
    watch(
      () => mainStore.canvasHeight,
      (val) => {
        canvasWidth.value = mainStore.canvasWidth;
        canvasHeight.value = val;
      }
    );

    watch(
      () => viewportStyles.value,
      (val) => {
        // console.log(screenStore.editCanvasLock)
        if (screenStore.editCanvasLock) {
          // console.log(val)
          mainStore.$patch({
            canvasWidth: val.width,
            canvasHeight: val.height,
          });
          canvasWidth.value = val.width;
          canvasHeight.value = val.height;
          height = val.height;
          width = val.width;
        }
        // slidesStore.setViewportRatio(val.height/val.width)
      },
      { immediate: true }
    );
    watch(
      () => slidesStore.viewportRatio,
      () => {
        screenStore.setEditCanvasLock(true);
      }
    );
    const setCanvasSize = () => {
      mainStore.$patch({
        canvasWidth: canvasWidth.value,
        canvasHeight: canvasHeight.value,
      });
    };
    const mousedown = (event: MouseEvent, directive: string) => {
      event.stopPropagation();
      var starty = event.clientY;
      var startx = event.clientX;
      // console.log("拖动按钮距离屏幕顶部的高度：", starty, startx)
      // var sb_bkx = startx - event.target.offsetLeft
      // var sb_bky = starty - event.target.offsetTop
      var ww = document.documentElement.clientWidth;
      var wh = window.innerHeight;
      if (event.preventDefault) {
        event.preventDefault();
      } else {
        event.returnValue = false;
      }
      function fnMove(ev: MouseEvent) {
        var event = ev || window.event;
        if (
          event.clientY < 0 ||
          event.clientX < 0 ||
          event.clientY > wh ||
          event.clientX > ww
        ) {
          return false;
        }
        var endx = event.clientX - startx;
        var endy = event.clientY - starty;
        // console.log(endy,endx)
        directive === "bot" ? (canvasHeight.value = height + endy) : "";
        directive === "right" ? (canvasWidth.value = width + endx) : "";
        directive === "left" ? (canvasWidth.value = width - endx) : "";
      }
      document.addEventListener("mousemove", fnMove, false);
      document.addEventListener("mouseup", () => {
        document.removeEventListener("mousemove", fnMove, false);
        // let doms = document.querySelectorAll('.viewport-wrapper') as unknown as HTMLElement[]
        // doms[0].style.transition = '.4s all ease'
        height = canvasHeight.value;
        width = canvasWidth.value;
        // top = canvasTop.value
        // left = canvasLeft.value
        setCanvasSize();
        let num = height / width;
        slidesStore.setViewportRatio(num.toFixed(2) as unknown as number);
      });
    };
    const mouseRight = (event: MouseEvent) => {
      event.stopPropagation();
    };

    const viewportRef = ref<HTMLElement>();

    const alignmentLines = ref<AlignmentLineProps[]>([]);

    const linkDialogVisible = ref(false);
    const openLinkDialog = () => (linkDialogVisible.value = true);

    watch(handleElementId, () => {
      mainStore.setActiveGroupElementId("");
    });

    const elementList = ref<PPTElement[]>([]);
    const setLocalElementList = () => {
      elementList.value = currentSlide.value
        ? JSON.parse(JSON.stringify(currentSlide.value.elements))
        : [];
    };
    watchEffect(setLocalElementList);

    useDropImageOrText(canvasEditRef);

    const { mouseSelectionState, updateMouseSelection } = useMouseSelection(
      elementList,
      viewportRef
    );

    const { dragElement } = useDragElement(elementList, alignmentLines);
    const { dragLineElement } = useDragLineElement(elementList);
    const { selectElement } = useSelectElement(elementList, dragElement);
    const { scaleElement, scaleMultiElement } = useScaleElement(
      elementList,
      alignmentLines
    );
    const { rotateElement } = useRotateElement(elementList, viewportRef);

    const { selectAllElement } = useSelectAllElement();
    const { deleteAllElements } = useDeleteElement();
    const { pasteElement } = useCopyAndPasteElement();
    const { enterScreening } = useScreening();
    const {
      copyAndPasteSlide,
      deleteSlide,
      updateSlideIndex,
      scrollToCurrent,
      createSlide,
    } = useSlideHandler();
    // 点击画布的空白区域：清空焦点元素、设置画布焦点、清除文字选区
    const handleClickBlankArea = (e: MouseEvent) => {
      e.preventDefault();
      e.stopPropagation();
      mainStore.setActiveElementIdList([]);
      if (!editorAreaFocus.value) mainStore.setEditorareaFocus(true);
      removeAllRanges();
      slidesStore.$patch({
        blankArea: true,
      });
    };

    // 移除画布编辑区域焦点
    const removeEditorAreaFocus = () => {
      if (editorAreaFocus.value) mainStore.setEditorareaFocus(false);
    };

    // 滚动鼠标
    const { scaleCanvas } = useScaleCanvas();
    const throttleScaleCanvas = throttle(scaleCanvas, 100, {
      leading: true,
      trailing: false,
    });
    const throttleUpdateSlideIndex = throttle(updateSlideIndex, 300, {
      leading: true,
      trailing: false,
    });

    const handleMousewheelCanvas = (e: WheelEvent) => {
      e.preventDefault();

      // 按住Ctrl键时：缩放画布
      if (ctrlKeyState.value) {
        if (e.deltaY > 0) throttleScaleCanvas("-");
        else if (e.deltaY < 0) throttleScaleCanvas("+");
      }
      // 上下翻页
      else {
        // mainStore.setCurrentTab(1)
        if (e.deltaY > 0) throttleUpdateSlideIndex(KEYS.DOWN);
        else if (e.deltaY < 0) throttleUpdateSlideIndex(KEYS.UP);
      }
    };

    // 开关网格线
    const toggleGridLines = () => {
      mainStore.setGridLinesState(!showGridLines.value);
    };

    // 在鼠标绘制的范围插入元素
    const { insertElementFromCreateSelection } =
      useInsertFromCreateSelection(viewportRef);
    const insertEle = (data: any) => {
      insertElementFromCreateSelection(data);
    };
    const contextmenus = (): ContextmenuItem[] => {
      return [
        {
          text: "粘贴",
          subText: "Ctrl + V",
          handler: pasteElement,
        },
        {
          text: "全选",
          subText: "Ctrl + A",
          handler: selectAllElement,
        },
        {
          text: "网格线",
          subText: showGridLines.value ? "√" : "",
          handler: toggleGridLines,
        },
        {
          text: "标尺",
          subText: showRuler.value ? "√" : "",
          handler: toggleRuler,
        },
        {
          text: "重置当前页",
          handler: deleteAllElements,
        },
        { divider: true },
        {
          text: "从当前页演示",
          subText: "Ctrl+F",
          handler: enterScreening,
        },
      ];
    };
    // 开关标尺
    const toggleRuler = () => {
      mainStore.setRulerState(!showRuler.value);
    };

    provide("slideScale", canvasScale);

    return {
      elementList,
      activeElementIdList,
      handleElementId,
      activeGroupElementId,
      canvasEditRef,
      viewportRef,
      viewportStyles,
      canvasScale,
      mouseSelectionState,
      currentSlide,
      creatingElement,
      alignmentLines,
      linkDialogVisible,
      openLinkDialog,
      handleClickBlankArea,
      removeEditorAreaFocus,
      insertElementFromCreateSelection,
      selectElement,
      rotateElement,
      scaleElement,
      dragLineElement,
      scaleMultiElement,
      handleMousewheelCanvas,
      contextmenus,
      insertEle,
      mousedown,
      canvasWidth,
      canvasHeight,
      canvasTop,
      canvasLeft,
      mouseRight,
      mouseover,
      slides,
      slideIndex,
      delPage,
      copyPage,
      createSlide,
      changSlideIndex,
      allowDrop,
      leaveDrop,
      drop,
      addPage,
      dragIndex,
      setCanvasSize,
      handlePage,
      // 协同
      websocketonmessage,
      showRuler,
      MultiPage,
      pageList,
      edtype,
    };
  },
});
</script>

<style lang="scss" scoped>
.viewport-content {
  height: 100%;
  overflow: hidden;
  position: relative;
}

.active {
  // outline: rgb(255, 186, 0) dashed 2px;
  outline: $themeColor solid 1px;
  z-index: 998;
}

.currentSlide {
  outline: 2px solid $buttonPrimary;
}

.opacity8 {
  opacity: 0.6;
}

.btn {
  position: absolute;
  bottom: -50px;
  left: 50%;
  margin-left: -65px;
  height: 30px;
  width: 130px;
  background-color: rgb(101, 101, 101);
  border-color: rgb(101, 101, 101);
  border-radius: 4px;
  text-align: center;
  line-height: 30px;
  color: #fff;
  cursor: pointer;
  opacity: 0.6;
  transition: 0.5s all ease;

  &:hover {
    opacity: 1;
  }
}

.resize {
  position: absolute;
  cursor: row-resize;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;

  &::after {
    content: "";
    box-sizing: border-box;
    position: absolute;
  }

  &:hover {
    dd {
      opacity: 1;
      background: #1890ff;
    }
  }
}

.resizebot,
.resizetop {
  width: 65px;
  height: 13px;
  bottom: -15px;
  left: 50%;
  margin-left: -32.5px;
  opacity: 1;

  dd {
    background: #656565;
    border-radius: 4px;
    width: 65px;
    height: 13px;
  }

  &::after {
    left: 20px;
    top: 4px;
    width: 23px;
    height: 5px;
    border-top: 1px solid #fff;
    border-bottom: 1px solid #fff;
  }
}

.resizetop {
  top: -13px;
  bottom: initial;
  opacity: 0;
}

.resizeRight,
.resizeLeft {
  width: 13px;
  height: 100%;
  cursor: ew-resize;
  right: -13px;
  top: 32px;
  margin-top: -33px;

  dd {
    background: #656565;
    border-radius: 4px;
    width: 13px;
    height: 65px;
  }

  &::after {
    left: 4px;
    top: 50%;
    margin-top: -11px;
    height: 23px;
    width: 5px;
    border-left: 1px solid #fff;
    border-right: 1px solid #fff;
  }
}

.resizeLeft {
  left: -13px;
  right: initial;
}

.canvas {
  height: 100%;
  user-select: none;
  overflow: hidden;
  // background-color: $canvasBgColor;
  position: relative;
  overflow-y: overlay;
  padding-top: 70px;
}

.viewport-wrapper {
  position: relative;
  box-shadow: 0 0 15px 0 rgba(0, 0, 0, 0.1);
  margin: 0 auto 100px auto;
  border-radius: 6px;
  box-sizing: border-box;

  .page {
    position: absolute;
    top: -33px;
    left: 10px;
    font-size: 18px;
    color: #c4c4ce;
  }

  .icongroup {
    position: absolute;
    top: -40px;
    right: 10px;

    .appIcon-iconfont {
      display: inline-block;
      text-align: center;
      line-height: 30px;
      font-size: 16px;
      color: rgb(196, 196, 206);
      width: 30px;
      height: 30px;
      background: rgb(47, 48, 67);
      border-radius: 50%;
      margin-left: 10px;
      cursor: pointer;

      &:hover {
        background: rgb(80, 81, 106);
        color: rgb(245, 245, 251);
      }
    }
  }
}

.viewport {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
}
</style>
